﻿using Microsoft.EntityFrameworkCore;

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

using ZFB.Models;
using ZFB.Models.EntityConfig;
using ZFB.Repository.Extensions;

namespace ZFB.Repository
{
    public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity, new()
    {
        private readonly MyDbContext db;

        public BaseRepository(MyDbContext db)
        {
            this.db = db;
        }

        #region 异步版本

        /// <summary>
        /// 添加一条数据
        /// </summary>
        /// <param name="param">T</param>
        /// <returns></returns>
        public async Task<int> AddAsync(T param)
        {
            await db.AddAsync(param);
            if (await db.SaveChangesAsync() >= 1)
                return 1;
            return 0;
        }

        /// <summary>
        /// 批量添加数据
        /// </summary>
        /// <param name="param">List<T></param>
        /// <returns></returns>
        public async Task<int> AddListAsync(List<T> param)
        {

            await db.AddRangeAsync(param);
            if (await db.SaveChangesAsync() >= 1)
                return 1; else return 0;


        }

        /// <summary>
        /// 获得一条数据
        /// </summary>
        /// <param name="where">查询条件</param>
        /// <returns></returns>
        public virtual async Task<T> GetModelAsync(Expression<Func<T, bool>> whereExpression)
        {
            return await db.Set<T>().Where(e=>!e.IsDeleted).SingleOrDefaultAsync(whereExpression);
        }

        /// <summary>
        /// 分页
        /// </summary>LongLongCountAsync
        /// <param name="page">当前页</param>
        /// <param name="limit">一页多少条</param>
        /// <returns></returns>
        public virtual async Task<Page<T>> GetPagesAsync(int page, int limit)
        {
            Page<T> pages = new();
            var count = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .LongCountAsync();
            pages.Items = await db.Set<T>()
                .Where(e => !e.IsDeleted)
            .AsNoTracking()
                .Skip((page - 1) * limit)
                .Take(limit)
                .ToListAsync();
            pages.TotalItems = count;
            pages.TotalPages = (int)Math.Ceiling(count * 10f / limit);
            pages.ItemsPerPage = limit;
            pages.CurrentPage = page;

            return pages;
        }
        public virtual async Task<Page<T>> GetPagesAsync(int page, int limit, Expression<Func<T, object>> orderExpression)
        {
            Page<T> pages = new();
            var count = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .LongCountAsync();
            pages.Items = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .OrderBy(orderExpression)
                .AsNoTracking()
                .Skip((page - 1) * limit)
                .Take(limit)
                .ToListAsync();
            pages.TotalItems = count;
            pages.TotalPages = (int)Math.Ceiling(count * 10f / limit);
            pages.ItemsPerPage = limit;
            pages.CurrentPage = page;

            return pages;
        }
        public virtual async Task<Page<T>> GetPagesAsync(int page, int limit, Expression<Func<T, bool>> whereExpression)
        {
            Page<T> pages = new();
            var count = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .Where(whereExpression)
                .LongCountAsync();
            pages.Items = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .Where(whereExpression)
                .AsNoTracking()
                .Skip((page - 1) * limit)
                .Take(limit)
                .ToListAsync();
            pages.TotalItems = count;
            pages.TotalPages = (int)Math.Ceiling(count * 10f / limit);
            pages.ItemsPerPage = limit;
            pages.CurrentPage = page;

            return pages;
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="limit">一页多少条</param>
        /// <param name="whereExpression">查询条件</param>
        /// <param name="orderExpression">排序值</param>
        /// <param name="isAsc">是否升序</param>
        /// <returns></returns>
        public async Task<Page<T>> GetPagesAsync(int page, int limit, Expression<Func<T, bool>> whereExpression,
            Expression<Func<T, object>> orderExpression)
        {
            Page<T> pages = new();
            var count = await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .Where(whereExpression)
                .LongCountAsync();
            pages.Items = await db.Set<T>().Where(whereExpression)
                .Where(e => !e.IsDeleted)
                .OrderBy(orderExpression)
                .AsNoTracking()
                .Skip((page - 1) * limit)
                .Take(limit)
                .ToListAsync();
            pages.TotalItems = count;
            pages.TotalPages = (int)Math.Ceiling(count * 10f / limit);
            pages.ItemsPerPage = limit;
            pages.CurrentPage = page;

            return pages;
        }


        /// <summary>
        /// 获得列表
        /// </summary>
        /// <param name="whereExpression">查询条件</param>
        /// <param name="orderExpression">排序值</param>
        /// <returns></returns>
        public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression,
            Expression<Func<T, object>> orderExpression)
        {
            var query = db.Set<T>()
              .Where(e => !e.IsDeleted)
              .AsNoTracking()
              .Where(whereExpression)
              .OrderBy(orderExpression)
              .AsNoTracking();
            return await query.ToListAsync();
        }
        /// <summary>
		/// 获得列表
		/// </summary>
		/// <param name="whereExpression">查询条件</param>
		/// <returns></returns>
        public virtual async Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression)
        {
            return await db.Set<T>()
                .Where(e => !e.IsDeleted)
                //.AsNoTracking()
                .Where(whereExpression)
                .ToListAsync();
        }
        /// <summary>
        /// 获得列表
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<T>> GetListAsync()
        {
            return await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .AsNoTracking()
                .ToListAsync();
        }
        /// <summary>
        /// 修改一条数据
        /// </summary>
        /// <param name="param">T</param>
        /// <returns></returns>
        public async Task<int> UpdateAsync(T param)
        {
            //db.Set<T>().Update(param);
            if (await db.SaveChangesAsync() >= 1)
                return 1;
            else return 0;
        }

        /// <summary>
        /// 批量修改
        /// </summary>
        /// <param name="param">T</param>
        /// <returns></returns>
        public async Task<int> UpdateAsync(List<T> param)
        {
            db.Set<T>().UpdateRange(param);
            if (await db.SaveChangesAsync() >= 1)
                return 1;
            else return 0;
        }

        /// <summary>
        /// 软删除
        /// </summary>
        /// <param name="columnsExpression">修改的列</param>
        /// <param name="whereExpression">判断条件</param>
        /// <returns></returns>
        public async Task<int> UpdateIsDeleteAsync(Expression<Func<T, bool>> whereExpression)
        {
            return await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .Where(whereExpression).ExecuteUpdateAsync(e=>e.SetProperty(e
                =>e.IsDeleted,e=>true));
        }

        /// <summary>
        /// 删除一条或多条数据
        /// </summary>
        /// <param name="param">string</param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(List<int> param)
        {
            foreach (var item in param)
            {
              await db.Set<T>().Where(e => e.Id == item).ExecuteDeleteAsync();
            }
            return 1;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="whereExpression">Expression<Func<T, bool>></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(Expression<Func<T, bool>> whereExpression)
        {
            await db.Set<T>().Where(whereExpression).ExecuteDeleteAsync();
            return 1;
        }
        /// <summary>
        /// 查询多少条
        /// </summary>
        /// <param name="whereExpression">查询条件</param>
        /// <returns></returns>
        public async Task<long> LongCountAsync(Expression<Func<T, bool>> whereExpression)
        {
           return await db.Set<T>()
                .AsNoTracking()
                .Where(e => !e.IsDeleted).Where(whereExpression).LongCountAsync();
        }
        /// <summary>
        /// 是否存在
        /// </summary>
        /// <param name="whereExpression">查询条件</param>
        /// <returns></returns>
        public async Task<bool> IsExistAsync(Expression<Func<T, bool>> whereExpression)
        {
            if (await db.Set<T>()
                .Where(e => !e.IsDeleted)
                .SingleOrDefaultAsync(whereExpression) != null)
            return true;
            return false;
        }

        /// <summary>
        /// 多表查询
        /// </summary>
        /// <typeparam name="T1">表1</typeparam>
        /// <typeparam name="T2">表2</typeparam>
        /// <typeparam name="T3">表3</typeparam>
        /// <typeparam name="TResult">结果</typeparam>
        /// <param name="joinExpression">连接条件</param>
        /// <param name="selectExpression">投影</param>
        /// <param name="whereExpression">查询条件</param>
        /// <returns></returns>
        public async Task<List<TResult>> QueryMuch<T1, T2, T3, TResult>(
            Expression<Func<T1, T2, T3, object[]>> joinExpression,
            Expression<Func<T1, T2, T3, TResult>> selectExpression,
            Expression<Func<T1, T2, T3, bool>> whereExpression = null) where T1 : class, new()
        {
            throw new NotImplementedException();
        }

       
        #endregion

    }
} 
